﻿using System;
using System.Reflection;

namespace Net.Adapter
{
    public abstract class RpcMethodPtr
    {
        public byte cmd;
        public MethodInfo method;
        public virtual Type GetActionType { get; }
        public virtual void SetPtr(Delegate ptr) { }
        public virtual void Invoke(object target, object[] pars) { }

        public virtual RpcMethodPtr Clone(object target)
        {
            var rpcMethodPtr = CreateMethodPtr();
            var actionDelegate = Delegate.CreateDelegate(GetActionType, target, method);
            rpcMethodPtr.SetPtr(actionDelegate);
            rpcMethodPtr.cmd = cmd;
            rpcMethodPtr.method = method;
            return rpcMethodPtr;
        }
        public abstract RpcMethodPtr CreateMethodPtr();
    }

    public class RpcMethodPtrNull : RpcMethodPtr
    {
        public Action ptr;
        public override Type GetActionType => typeof(Action);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr();
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtrNull();
    }

    public class RpcMethodPtr<T> : RpcMethodPtr
    {
        public Action<T> ptr;
        public override Type GetActionType => typeof(Action<T>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T>();
    }

    public class RpcMethodPtr<T, T1> : RpcMethodPtr
    {
        public Action<T, T1> ptr;
        public override Type GetActionType => typeof(Action<T, T1>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1>();
    }

    public class RpcMethodPtr<T, T1, T2> : RpcMethodPtr
    {
        public Action<T, T1, T2> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2>();
    }

    public class RpcMethodPtr<T, T1, T2, T3> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4, T5> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4, T5> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4, T5>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4, T5>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4], (T5)pars[5]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4, T5>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4, T5, T6> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4, T5, T6> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4, T5, T6>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4, T5, T6>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4], (T5)pars[5], (T6)pars[6]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4, T5, T6>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4, T5, T6, T7> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4, T5, T6, T7>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4, T5, T6, T7>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4], (T5)pars[5], (T6)pars[6], (T7)pars[7]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7, T8> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4, T5, T6, T7, T8> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4, T5, T6, T7, T8>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4, T5, T6, T7, T8>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4], (T5)pars[5], (T6)pars[6], (T7)pars[7], (T8)pars[8]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7, T8>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7, T8, T9> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4], (T5)pars[5], (T6)pars[6], (T7)pars[7], (T8)pars[8], (T9)pars[9]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>();
    }

    public class RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : RpcMethodPtr
    {
        public Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ptr;
        public override Type GetActionType => typeof(Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>);
        public override void SetPtr(Delegate ptr)
        {
            this.ptr = ptr as Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>;
        }
        public override void Invoke(object target, object[] pars)
        {
            ptr((T)pars[0], (T1)pars[1], (T2)pars[2], (T3)pars[3], (T4)pars[4], (T5)pars[5], (T6)pars[6], (T7)pars[7], (T8)pars[8], (T9)pars[9], (T10)pars[10]);
        }
        public override RpcMethodPtr CreateMethodPtr() => new RpcMethodPtr<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>();
    }
}
